package com.keba.lamp.complaint.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.keba.basic.annotation.log.WebLog;
import com.keba.basic.annotation.user.LoginUser;
import com.keba.basic.base.R;
import com.keba.basic.base.controller.SuperController;
import com.keba.basic.base.request.PageParams;
import com.keba.basic.context.ContextConstants;
import com.keba.basic.context.ContextUtil;
import com.keba.basic.database.mybatis.conditions.Wraps;
import com.keba.basic.database.mybatis.conditions.query.LbQueryWrap;
import com.keba.basic.database.mybatis.conditions.query.QueryWrap;
import com.keba.basic.exception.BizException;
import com.keba.basic.interfaces.echo.EchoService;
import com.keba.lamp.common.constant.BizConstant;
import com.keba.lamp.complaint.entity.*;
import com.keba.lamp.complaint.enumeration.DocTemplateTypeEnum;
import com.keba.lamp.complaint.manager.ChannelCustomerManager;
import com.keba.lamp.complaint.manager.DefendantManager;
import com.keba.lamp.complaint.manager.PlaintffManager;
import com.keba.lamp.complaint.service.*;
import com.keba.lamp.complaint.vo.query.CaseComponentQuery;
import com.keba.lamp.complaint.vo.query.CasePageQuery;
import com.keba.lamp.complaint.vo.result.CaseResultVO;
import com.keba.lamp.complaint.vo.result.EvidenceResultVO;
import com.keba.lamp.complaint.vo.result.ShareInfoResultVO;
import com.keba.lamp.complaint.vo.save.CaseFileUploadVO;
import com.keba.lamp.complaint.vo.save.CaseSaveVO;
import com.keba.lamp.complaint.vo.update.CaseSendEmailVO;
import com.keba.lamp.complaint.vo.update.CaseShareLinkVO;
import com.keba.lamp.complaint.vo.update.CaseUpdateComplaintContentVO;
import com.keba.lamp.complaint.vo.update.CaseUpdateVO;
import com.keba.lamp.file.entity.Appendix;
import com.keba.lamp.file.entity.File;
import com.keba.lamp.file.service.AppendixService;
import com.keba.lamp.file.service.FileService;
import com.keba.lamp.file.strategy.FileContext;
import com.keba.lamp.file.vo.result.FileResultVO;
import com.keba.lamp.model.entity.system.SysUser;
import com.keba.lamp.system.manager.system.DefParameterManager;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

import static com.keba.lamp.common.constant.SwaggerConstants.DATA_TYPE_MULTIPART_FILE;

/**
 * <p>
 * 前端控制器
 * 诉讼状案件
 * </p>
 *
 * @author twg
 * @date 2025-03-14 21:47:52
 * @create [2025-03-14 21:47:52] [twg] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Validated
@RestController
@RequestMapping("/case")
@Tag(name = "诉讼状案件")
public class CaseController extends SuperController<CaseService, Long, Case
        , CaseSaveVO, CaseUpdateVO, CasePageQuery, CaseResultVO> {
    private final EchoService echoService;
    private final EvidenceComponentCaseTypeRelService evidenceComponentCaseTypeRelService;
    private final DefendantManager defendantManager;
    private final PlaintffManager plaintffManager;
    private final ChannelCustomerService channelCustomerService;
    private final ChannelCustomerManager channelCustomerManager;
    private final PdfCommonService pdfCommonService;
    private final DefParameterManager defParameterManager;
    private final AppendixService appendixService;
    private final FileService fileService;
    private final DocTemplateService docTemplateService;


    @Override
    public EchoService getEchoService() {
        return echoService;
    }

    @Override
    public void handlerResult(IPage<CaseResultVO> page) {
        super.handlerResult(page);
        List<CaseResultVO> records = page.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            records.forEach(resultVO -> {
                if (Objects.nonNull(resultVO.getChannelCustomerId())) {
                    ChannelCustomer channelCustomer = channelCustomerManager.getById(resultVO.getChannelCustomerId());
                    resultVO.setChannelCustomer(Objects.nonNull(channelCustomer) ? channelCustomer.getName() : "");
                }
            });
        }
    }

    @Override
    public IPage<Case> query(PageParams<CasePageQuery> params) {
        Long tenantId = ContextUtil.getTenantId();
        IPage<Case> pageResult = super.query(params);
        //handlerWrapper可能会清除tenantid，这里再设置回去，接口后续逻辑可能会用到
        ContextUtil.setTenantId(tenantId);
        return pageResult;
    }

    @Override
    public QueryWrap<Case> handlerWrapper(Case model, PageParams<CasePageQuery> params) {
        String clientId = ContextUtil.getClientId();
        Long tenantId = ContextUtil.getTenantId();
        Long userId = ContextUtil.getUserId();
        String appId = ContextUtil.getAppId();
        log.info("分页查询案件请求头:clientId:{}, tenantId:{}, userId:{}, appID:{}", clientId, tenantId, userId, appId);
        QueryWrap<Case> wrap = super.handlerWrapper(model, params);
        LbQueryWrap<Case> wrapper = wrap.lambda();
        String aggregateSearch = params.getModel().getAggregateSearch();
        if (StringUtils.isNotBlank(aggregateSearch)) {
            List<Plaintff> plaintffs = plaintffManager.queryByName(aggregateSearch);
            List<Defendant> defendants = defendantManager.queryByName(aggregateSearch);
            Set<Long> plaintffCaseIdSet = CollectionUtils.isNotEmpty(plaintffs) ? plaintffs.stream().map(Plaintff::getCaseId).collect(Collectors.toSet()) : null;
            Set<Long> defendantCaseIdSet = CollectionUtils.isNotEmpty(defendants) ? defendants.stream().map(Defendant::getCaseId).collect(Collectors.toSet()) : null;
            wrapper.like(Case::getCaseName, aggregateSearch)
                    .or().in(CollectionUtils.isNotEmpty(plaintffCaseIdSet), Case::getId, plaintffCaseIdSet)
                    .or().in(CollectionUtils.isNotEmpty(defendantCaseIdSet), Case::getId, defendantCaseIdSet)
                    .or().like(Case::getCaseRemark, aggregateSearch)
            ;
            if (NumberUtil.isLong(aggregateSearch)) {
                wrapper.or().like(Case::getId, Long.parseLong(aggregateSearch))
                ;
            }
        }
        String personName = params.getModel().getPersonName();
        if (StringUtils.isNotBlank(personName)) {
            List<Plaintff> plaintffs = plaintffManager.queryByName(personName);
            List<Defendant> defendants = defendantManager.queryByName(personName);
            if (CollectionUtils.isEmpty(plaintffs) && CollectionUtils.isEmpty(defendants)) {
                wrapper.eq(Case::getId, -1L);
            } else {
                Set<Long> plaintffCaseIdSet = plaintffs.stream().map(Plaintff::getCaseId).collect(Collectors.toSet());
                Set<Long> defendantCaseIdSet = defendants.stream().map(Defendant::getCaseId).collect(Collectors.toSet());
                plaintffCaseIdSet.addAll(defendantCaseIdSet);
                wrapper.in(Case::getId, plaintffCaseIdSet);
            }
        }
        String channelCustomer = params.getModel().getChannelCustomer();
        if (StringUtils.isNotBlank(channelCustomer)) {
            ChannelCustomer query = new ChannelCustomer();
            query.setName(channelCustomer);
            QueryWrap<ChannelCustomer> queryWrap = Wraps.q(query);
            List<ChannelCustomer> channelCustomerList = channelCustomerService.list(queryWrap);
            if (CollectionUtils.isEmpty(channelCustomerList)) {
                wrapper.eq(Case::getId, -1L);
            } else {
                Set<Long> channelCustomerIdSet = channelCustomerList.stream().map(ChannelCustomer::getId).collect(Collectors.toSet());
                wrapper.in(Case::getChannelCustomerId, channelCustomerIdSet);
            }
        }
        boolean h5Req = superService.isH5Req();
        //如果是H5页面请求，且非特定租户，需要加上userId和APPID条件，并清除tenantID条件
        if (h5Req) {
            Map<String, String> localMap = ContextUtil.getLocalMap();
            localMap.remove(ContextConstants.TENANT_ID_HEADER);
            localMap.remove(ContextConstants.TENANT_BASE_POOL_NAME_HEADER);
            localMap.remove(ContextConstants.TENANT_EXTEND_POOL_NAME_HEADER);
            //appid为空时，直接返回空数据
            wrapper.eq(Case::getUserId, userId).eq(Case::getAppId, StringUtils.isNotBlank(appId) ? appId : "-1");
        }
        return wrap;
    }

    @Override
    public R<Case> handlerUpdate(CaseUpdateVO updateVO) {
        //boolean enableUpdate = superService.enableUpdate(updateVO.getId());
        //ArgumentAssert.isTrue(enableUpdate, "该案件已生成起诉状，无法编辑");
        return super.handlerUpdate(updateVO);
    }

    @Override
    public R<Boolean> handlerDelete(List<Long> ids) {
        // 这个操作相当的危险，请谨慎操作！！!
        return success(superService.delete(ids));
    }

    @Override
    public R<CaseResultVO> get(@PathVariable Long id) {
        CaseResultVO caseResultVO = superService.getCaseById(id);
        echoService.action(caseResultVO);
        return success(caseResultVO);
    }

    @Override
    public R<CaseResultVO> getDetail(@RequestParam("id") Long id) {
        CaseResultVO caseResultVO = superService.getCaseById(id);
        echoService.action(caseResultVO);
        return R.success(caseResultVO);
    }

    @Operation(summary = "查询证据列表", description = "查询证据列表")
    @PostMapping("/queryEvidenceList")
    @WebLog("查询证据列表")
    public R<List<EvidenceResultVO>> queryEvidenceList(@RequestBody CaseComponentQuery data) {
        Long caseId = data.getCaseId();
        String bizType = data.getBizType();
        String caseType = data.getCaseType();
        List<EvidenceResultVO> evidenceResultVOList = null;
        if (Objects.nonNull(caseId)) {
            evidenceResultVOList = superService.getEvidenceList(caseId, bizType, caseType);
        }
        if (CollectionUtil.isEmpty(evidenceResultVOList)) {
            evidenceResultVOList = evidenceComponentCaseTypeRelService.queryEvidenceCaseTypeRel(bizType, caseType);
        }
        return success(evidenceResultVOList);
    }

    @Operation(summary = "新增页面-生成诉讼状")
    @PostMapping("/saveGenerateCase")
    @WebLog(value = "生成诉讼状", request = false)
    public R<Boolean> saveGenerateCase(@RequestBody @Validated CaseSaveVO saveVO) {
        this.superService.enableCallAi(saveVO);
        Case caseEntity = this.superService.save(saveVO);
        try {
            boolean result = this.superService.callAi(caseEntity.getId());
            return result ? R.success() : R.fail("生成起诉状失败");
        } catch (BizException e) {
            log.error("生成起诉状失败", e);
            return R.fail(e.getMessage());
        } catch (Exception e) {
            log.error("生成起诉状失败", e);
            return R.fail("生成起诉状失败");
        }
    }

    @Operation(summary = "编辑页面-生成诉讼状")
    @PostMapping("/updateGenerateCase")
    @WebLog(value = "生成诉讼状", request = false)
    public R<Boolean> updateGenerateCase(@RequestBody @Validated CaseUpdateVO updateVO) {
        this.superService.enableCallAi(updateVO);
        this.superService.updateById(updateVO);
        try {
            boolean result = this.superService.callAi(updateVO.getId());
            return result ? R.success() : R.fail("生成起诉状失败");
        } catch (BizException e) {
            log.error("生成起诉状失败", e);
            return R.fail(e.getMessage());
        } catch (Exception e) {
            log.error("生成起诉状失败", e);
            return R.fail("生成起诉状失败");
        }
    }

    @Operation(summary = "重新生成AI文书")
    @GetMapping("/generateCase")
    @WebLog(value = "重新生成AI文书", request = false)
    public R<Boolean> generateCase(@RequestParam("id") Long id) {
        CaseResultVO caseResultVO = this.superService.getCaseById(id);
        this.superService.enableCallAi(caseResultVO);
        try {
            boolean result = this.superService.callAi(id);
            return result ? R.success() : R.fail("生成AI文书失败");
        } catch (BizException e) {
            log.error("生成AI文书失败", e);
            return R.fail(e.getMessage());
        } catch (Exception e) {
            log.error("生成AI文书失败", e);
            return R.fail("生成AI文书失败");
        }
    }

    @Operation(summary = "下载起诉状")
    @GetMapping(value = "/downCasePdf", produces = "application/octet-stream")
    @WebLog(value = "下载起诉状", request = false)
    public void downCasePdf(@RequestParam Long id,
                            @RequestParam(required = false) String type,
                            HttpServletResponse response) {
        // 设置文件下载Header
        try {
            String fileType = StringUtils.isBlank(type) ? "pdf" : type;
            CaseResultVO caseResultVO = this.superService.getCaseById(id);
            //ArgumentAssert.notNull(caseResultVO.getLastGenerateTime(), "起诉状未生成，无法下载");
            if (!BizConstant.CASE_STATE_SUCCESS_10.equals(caseResultVO.getCaseState())) {
                throw new BizException("起诉状未生成，无法下载");
            }
            response.reset();
            String fileName = caseResultVO.getCaseName() + "起诉书." + fileType;
            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
            response.setContentType("application/octet-stream; charset=UTF-8");
            ServletOutputStream outputStream = response.getOutputStream();
            pdfCommonService.createCasePdf(caseResultVO, outputStream, fileType);
        } catch (Exception e) {
            log.error("下载诉讼状失败:", e);
            throw new BizException("下载诉讼状失败");
        }
    }

    @Operation(summary = "下载证据文件包")
    @GetMapping(value = "/downEvidenceZip", produces = "application/octet-stream")
    @WebLog(value = "下载证据文件包", request = false)
    public void downEvidenceZip(@RequestParam Long id,
                                @RequestParam(required = false) String type,
                                HttpServletResponse response) {
        // 设置文件下载Header
        try {
            CaseResultVO caseResultVO = this.superService.getCaseById(id);
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(caseResultVO.getCaseName() + "证据.zip"));
            response.setContentType("application/octet-stream; charset=UTF-8");
            ServletOutputStream outputStream = response.getOutputStream();

            pdfCommonService.createEvidenceZip(caseResultVO, outputStream);
            outputStream.close();
        } catch (Exception e) {
            log.error("下载证据失败:", e);
            throw new BizException("下载证据失败");
        }
    }

    @Operation(summary = "下载证据目录")
    @GetMapping(value = "/downEvidencePdf", produces = "application/octet-stream")
    @WebLog(value = "下载证据目录", request = false)
    public void downEvidencePdf(@RequestParam Long id,
                                @RequestParam(required = false) String type,
                                HttpServletResponse response) {
        // 设置文件下载Header
        try {

            CaseResultVO caseResultVO = this.superService.getCaseById(id);
            response.reset();
            String fileType = StringUtils.isBlank(type) ? "pdf" : type;
            String fileName = caseResultVO.getCaseName() + "证据目录." + fileType;
            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
            response.setContentType("application/octet-stream; charset=UTF-8");

            ServletOutputStream outputStream = response.getOutputStream();
            pdfCommonService.createEvidencePdf(caseResultVO, outputStream, fileType);

            outputStream.close();
        } catch (Exception e) {
            log.error("下载证据目录失败:", e);
            throw new BizException("下载证据目录失败");
        }
    }

    @Operation(summary = "修改起诉状")
    @PostMapping("/updateComplaintContent")
    @WebLog(value = "修改起诉状", request = false)
    public R updateComplaintContent(@RequestBody @Validated CaseUpdateComplaintContentVO caseUpdateComplaintContentVO) {
        boolean result = this.superService.updateComplaintContent(caseUpdateComplaintContentVO);
        return result ? R.success() : R.fail("修改失败");
    }

    @Operation(summary = "下载案件压缩包")
    @GetMapping(value = "/downCaseZip", produces = "application/octet-stream")
    @WebLog(value = "下载证据文件包", request = false)
    public void downCaseZip(@RequestParam Long id,
                            HttpServletResponse response) {
        // 设置文件下载Header
        try {
            CaseResultVO caseResultVO = this.superService.getCaseById(id);
            if (!BizConstant.CASE_STATE_SUCCESS_10.equals(caseResultVO.getCaseState())) {
                throw new BizException("案件未完成，无法下载");
            }
            String caseName = StringUtils.isBlank(caseResultVO.getCaseName()) ? "" : caseResultVO.getCaseName();
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(caseName + "立案材料.zip"));
            response.setContentType("application/octet-stream; charset=UTF-8");
            ServletOutputStream outputStream = response.getOutputStream();
            pdfCommonService.createCaseZip(caseResultVO, outputStream);
            outputStream.close();
        } catch (Exception e) {
            log.error("下载证据失败:", e);
            throw new BizException("下载证据失败");
        }
    }

    @Operation(summary = "生成分享链接")
    @PostMapping("/createShareLink")
    @WebLog(value = "生成分享链接", request = false)
    public R createShareLink(@RequestBody @Validated CaseShareLinkVO caseShareLinkVO) {
        ShareInfoResultVO shareLinkResultVO = this.superService.createShareLink(caseShareLinkVO.getId(), caseShareLinkVO.getPhone());
        return R.success(shareLinkResultVO);
    }

    @Operation(summary = "发送邮箱")
    @PostMapping("/sendEmail")
    @WebLog(value = "生成分享链接", request = false)
    public R sendEmail(@RequestBody @Validated CaseSendEmailVO caseSendEmailVO,
                       @Parameter(hidden = true) @LoginUser(isEmployee = true) SysUser sysUser) {
        Boolean result = this.superService.sendEmail(caseSendEmailVO, sysUser);
        return result ? R.success("邮件发送成功") : R.fail("邮件发送失败");
    }

    @Operation(summary = "查询案件状态")
    @GetMapping("/getCaseState")
    @WebLog(value = "查询案件状态", request = false)
    public R getCaseState(@RequestParam Long id) {
        String state = this.superService.getCaseState(id);
        return R.success(state);
    }

    /**
     * 上传签名文件
     *
     * @param file         上传签名文件
     * @param fileUploadVO 附件信息
     */
    @Operation(summary = "上传签名文件", description = "上传签名文件")
    @Parameters({
            @Parameter(name = "file", description = "附件", schema = @Schema(type = DATA_TYPE_MULTIPART_FILE), in = ParameterIn.QUERY, required = true),
    })
    @PostMapping(value = "/signature/upload")
    @WebLog("上传签名文件")
    public R<FileResultVO> upload(@RequestParam(value = "file") MultipartFile file,
                                  @Validated CaseFileUploadVO fileUploadVO) {
        return R.success(this.superService.upload(file, fileUploadVO));
    }

    /**
     * 删除签名文件
     */
    @Operation(summary = "删除签名文件")
    @DeleteMapping(value = "/signature/delete")
    @WebLog("'删除签名文件:' + #ids")
    public R<Boolean> deleteSignatureFile(@RequestBody List<Long> fileIds) {
        return R.success(this.superService.deleteSignatureFile(fileIds));
    }


    @Operation(summary = "根据案件id下载文书文件", description = "根据案件id下载文书文件")
    @Parameters({
            @Parameter(name = "caseId", description = "案件id"),
            @Parameter(name = "type", description = "文书类型 01 送达文书 02 银行结算")
    })
    @GetMapping(value = "/downloadDocTemplate", produces = "application/octet-stream")
    @WebLog("下载文件")
    public void download(@RequestParam Long caseId, @RequestParam String type, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Case aCase = superService.getById(caseId);
        if (aCase == null) {
            return;
        }
        List<Long> ids = new ArrayList<>();
        ids.add(caseId);
        List<DocTemplate> docTemplates = docTemplateService.list(Wraps.<DocTemplate>lbQ().eq(DocTemplate::getCaseId, caseId));
        if (CollUtil.isNotEmpty(docTemplates)) {
            ids.addAll(docTemplates.stream().map(DocTemplate::getId).collect(Collectors.toList()));
        }
        List<Appendix> appendices = appendixService.list(Wraps.<Appendix>lbQ().in(Appendix::getBizId, ids)
                .eq(Appendix::getBizType, DocTemplateTypeEnum.getByCode(type).getDesc()));

        fileService.download(request, response, DocTemplateTypeEnum.getByCode(type).getLabel() + "等.zip",
                appendices.stream().map(Appendix::getId).collect(Collectors.toList()));
    }
}


